
#include "Simple_window.h"
#include "Graph.h"
#include <FL/Fl_Menu_Bar.H>
#include <FL/Fl_File_Chooser.H>
#include <FL/Fl_Text_Display.H>

#include "Store_menu.h"
#include <iostream>

using namespace std;
using namespace Store;
using namespace Graph_lib;

//types we need

namespace Graph_lib {
//------------------------------------------------------------------------------
	struct Window_text_display : Widget {
		Window_text_display(Point XY, int W, int H, string L, Callback cb): Widget(XY, W, H, L, cb)
		{}
		void set_buffer(string s);
		void attach(Window&);
	private:
		Fl_Text_Buffer data;
		Fl_Text_Display *ptd;

	};
	void Window_text_display::attach(Window& win)
	{
		ptd = new Fl_Text_Display(loc.x, loc.y, width, height, label.c_str());
		ptd->buffer(&data);
		pw  = (Fl_Widget*) ptd;
		pw->callback(reinterpret_cast<Fl_Callback*>(do_it), &win); // pass the window
		own = &win;
	}
	void Window_text_display::set_buffer(string s) 
	{
		data.text(s.c_str());
	}

//------------------------------------------------------------------------------
	struct Menu_bar : Widget {
		Menu_bar(Point XY, int W, int H, Callback cb): Widget(XY, W, H, "", cb)
		{}
		void menu(Fl_Menu_Item *ma);
		void attach(Window&);
	private:
		Fl_Menu_Bar *pmb;
		Fl_Menu_Item *ma;

	};
	void Menu_bar::attach(Window& win)
	{
		pmb = new Fl_Menu_Bar(loc.x, loc.y, width, height);
		pmb->menu(ma);
		pw  = (Fl_Widget*) pmb;
		pw->callback(reinterpret_cast<Fl_Callback*>(do_it), &win); // pass the window
		own = &win;
	}
	void Menu_bar::menu(Fl_Menu_Item *m) 
	{
		ma = m;
	}
}

// ------------------------ Legend (RA Part2 C Extra) --------------------------
struct Legend : Shape {
public:
	Legend(Point loc, vector<string> data, string title);
	void move(int dx, int dy);
protected:
	void draw_lines() const;
private:
	Point loc;
	vector<string> data;
	Text* title;
	vector<Graph_lib::Rectangle*> rectangles;
	vector<Text*> texts;
	int rect_width;
	int rect_space;
};

Legend::Legend(Point loc, vector<string> data, string title): loc(loc), data(data), rect_width(20), rect_space(5) {
	// Title
	this->title = new Text(Point(loc.x, loc.y), title);
	int title_height = 20;

	int i = 0;
	for (vector<string>::const_iterator it = data.begin(); it != data.end(); ++it) {
		Point p(loc.x, loc.y + title_height + i * (rect_width + rect_space));

		// Rectangle
		Graph_lib::Rectangle* r = new Graph_lib::Rectangle(p, rect_width, rect_width);
		r->set_fill_color(i+1 % 256);
		r->set_color(i+1 % 256);
		rectangles.push_back(r);

		//Labels
		Text* t = new Text(p, *it);
		t->move(rect_space + rect_width, t->font_size());
		texts.push_back(t);

		++i;
	}
}

void Legend::move(int dx, int dy) {
	title->move(dx, dy);

	for (vector<Text*>::const_iterator it = texts.begin(); it != texts.end(); ++it) {
		(*it)->move(dx, dy);
	}

	for (vector<Graph_lib::Rectangle*>::const_iterator it = rectangles.begin(); it != rectangles.end(); ++it) {
		(*it)->move(dx, dy);
	}
}

void Legend::draw_lines() const {
	title->draw();

	for (vector<Text*>::const_iterator it = texts.begin(); it != texts.end(); ++it) {
		(*it)->draw();
	}

	for (vector<Graph_lib::Rectangle*>::const_iterator it = rectangles.begin(); it != rectangles.end(); ++it) {
		(*it)->draw();
	}
}

// ----------------------------- End Legend ------------------------------------

//header declarations
void displayC2(Graph_lib::Window&, Store_menu&);
void do_about_box(Graph_lib::Window&);
void do_help_box(Graph_lib::Window&); //vsr part 2
void do_read(Graph_lib::Window&, Store_menu&, string, string, Msg_type);
void do_largest_check_out_cart(Graph_lib::Window&, Store_menu&); // RA Part2 B1
void b2_box(Graph_lib::Window&, Store_menu&);
void do_displayB3(Graph_lib::Window&, Store_menu&);
void do_graph_total_sales_by_category_and_month(Graph_lib::Window&, Store_menu&);	// RA Part2 C extra
void do_graph_total_sales_by_customer(Graph_lib::Window&, Store_menu&);				// RT part 2 C3
void Main_Window_CB(Fl_Widget*, void*);
void Menu_Bar_CB (Fl_Widget*, void*);

//global data
bool main_window_click = false;
bool menu_bar_click = false;
bool main_click_enabled = true;//force serialization on sclicks
int window_userdata;

//main window menu bar
//Note: for expediancy sake to define the menu bar below we used an FLTK type Fl_Menu_Item. 
//This makes our program  directly depend on FLTK instead of our interface Graph_lib.
//We don't like this, but we did it to save time, which often happens in the real world.
//A better solution is to write code to hide this in the implementation of our Graph_lib::Menu_bar
//An interesting exercise is to see if you can eliminate direct references in our code to FLTK types 
Fl_Menu_Item menu_bar[] = {
 {"Read", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0},
 {"Customers", 0,  (Fl_Callback*)Main_Window_CB, Address (Read_customers), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Carts", 0,  (Fl_Callback*)Main_Window_CB, Address (Read_carts), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Category/Products", 0,  (Fl_Callback*)Main_Window_CB, Address (Read_category_products), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {0,0,0,0,0,0,0,0,0},
 {"Show", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0},
 {"Categories", 0,  (Fl_Callback*)Main_Window_CB, Address (Show_categories), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Customers", 0,  (Fl_Callback*)Main_Window_CB, Address (Show_customers), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Products", 0,  (Fl_Callback*)Main_Window_CB, Address (Show_products), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Cart Items", 0,  (Fl_Callback*)Main_Window_CB, Address (Show_cart_items), 0, FL_NORMAL_LABEL, 0, 14, 0}, //VSR part 2
 {"Carts", 0,  (Fl_Callback*)Main_Window_CB, Address (Show_carts), 0, FL_NORMAL_LABEL, 0, 14, 0}, //VSR part 2
 {"Largest Check Out", 0,  (Fl_Callback*)Main_Window_CB, Address (Show_check_out), 0, FL_NORMAL_LABEL, 0, 14, 0}, // RA Part2 B1
 {"Top Five Products by Sales",  0,  (Fl_Callback*)Main_Window_CB, Address (Show_top_five), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Top Three Cust-B3", 0,  (Fl_Callback*)Main_Window_CB, Address (Top3CustomerByPurchaseFrequency), 0, FL_NORMAL_LABEL, 0, 14, 0},	// RT -Part 2 - B
 {0,0,0,0,0,0,0,0,0},
 {"Find", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0},
 {"Category Sales", 0,  (Fl_Callback*)Main_Window_CB, Address (Find_category_sales), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Customer Sales", 0,  (Fl_Callback*)Main_Window_CB, Address (Find_customer_sales), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Product Sales", 0,  (Fl_Callback*)Main_Window_CB, Address (Find_product_sales), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {0,0,0,0,0,0,0,0,0},
 {"Update", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0},
 {"Add Cart Item", 0,  (Fl_Callback*)Main_Window_CB, Address (Update_add_cart_item), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Add Product", 0,  (Fl_Callback*)Main_Window_CB, Address (Update_add_product), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Add Customer", 0,  (Fl_Callback*)Main_Window_CB, Address (Update_add_customer), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {0,0,0,0,0,0,0,0,0},
 {"Graph", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0},																									// RA Part2 C1
 {"Total Sales by Month", 0,  (Fl_Callback*)Main_Window_CB, Address (Graph_total_sales_by_month), 0, FL_NORMAL_LABEL, 0, 14, 0},						// RA Part2 C1
 {"Total Sales by Customer", 0,  (Fl_Callback*)Main_Window_CB, Address (Graph_total_sales_by_customer), 0, FL_NORMAL_LABEL, 0, 14, 0},					// RA Part2 C1
 {"Total Sales by Category and Month", 0,  (Fl_Callback*)Main_Window_CB, Address (Graph_total_sales_by_category_month), 0, FL_NORMAL_LABEL, 0, 14, 0},	// RA Part2 C1
 {0,0,0,0,0,0,0,0,0},																																	// RA Part2 C1
 {"About", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0},
 {"Info", 0,  (Fl_Callback*)Main_Window_CB, Address (About_info), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Help", 0,  (Fl_Callback*)Main_Window_CB, Address (About_help), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {0,0,0,0,0,0,0,0,0},
 {"Exit", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0},
 {"Save and exit", 0,  (Fl_Callback*)Main_Window_CB, Address (Exit_program), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,0,0,0,0}
};


//call back functions
void cust_cb(Address addr, Address) // callback for customer button
{
	Main_Window_CB((Fl_Widget*) addr, Address (Customers_button));
}
void cart_cb(Address addr, Address) // callback for customer button
{
	Main_Window_CB((Fl_Widget*) addr, Address (Carts_button));
}
void cat_cb(Address addr, Address) // callback for customer button
{
	Main_Window_CB((Fl_Widget*) addr, Address (Categories_button));
}
void prod_cb(Address addr, Address) // callback for customer button
{
	Main_Window_CB((Fl_Widget*) addr, Address (Products_button));
}
void cart_items_cb(Address addr, Address) // callback for customer button
{
	Main_Window_CB((Fl_Widget*) addr, Address (Cart_items_button));
}
 void display_cb(Address addr, Address) // callback for display window
{
	Main_Window_CB((Fl_Widget*) addr, Address (Display_window));
}
 void menu_bar_cb(Address addr, Address)//callback for menu bar
 {
	 Menu_Bar_CB((Fl_Widget*) addr, Address (Menu_bar_cb));
 }

void Menu_Bar_CB (Fl_Widget*, void* ud) {
	cout << "Menu Bar Callback" << " Userdata=" << (int) ud << "\n";
	menu_bar_click = true;
}

void Main_Window_CB(Fl_Widget*, void* ud) {
	if(main_click_enabled)//don't signal the window click if main loop is active
	{
		cout << "Main Window Callback" << " Userdata=" << (int) ud << "\n";
		window_userdata = (int) ud;
		main_window_click = true;
		main_click_enabled = false; //main loop active on current click
	}
}
//wait functions for callbacks to be executed
void wait_for_main_window_click() {
	while (!main_window_click) 
		Fl::wait();
	main_window_click = false;
	Fl::redraw();
}

void wait_for_menu_bar_click() {
	while (!menu_bar_click)
		Fl::wait();
	menu_bar_click = false;
	Fl::redraw();
}

int main()
{
	//create the main window and display it
	Store_menu m;
    Graph_lib::Window sw(600, 500, "OnLine Store Report Program");
    Button cust(Point(40, 50), 100, 30, "Customers", cust_cb);
	sw.attach(cust);
	Button cart(Point(40, 100), 100, 30, "Carts", cart_cb);
	sw.attach(cart);
	Button cat(Point(40, 150), 100, 30, "Categories", cat_cb);
	sw.attach(cat);
	Button prod(Point(40, 200), 100, 30, "Products", prod_cb);
	sw.attach(prod);
	Button cart_items(Point(40, 250), 100, 30, "Cart Items", cart_items_cb);
	sw.attach(cart_items);
    sw.callback((Fl_Callback*)Main_Window_CB, Address (Exit_program));
	Menu_bar mb(Point(0, 0), 600, 30, menu_bar_cb);
    mb.menu(menu_bar);
	sw.attach(mb);

	Window_text_display t(Point(150,50),400, 400, "Data Display", display_cb );
	t.set_buffer("No Data Loaded\n");
	sw.attach(t);
 	sw.resizable(&sw);
	

	//main loop to execute user clicks on the main window
	try {
		
		while(true) {
			main_click_enabled = true;
			wait_for_main_window_click();
			cout << "Act on userdata = " << window_userdata << endl;
			switch(window_userdata) 
			{
				//need to complete all the menu cases
				case Read_customers:
					do_read(sw, m, "cust.dat", "Open Customer File", Read_customers);
					break;
				case Read_carts:
					do_read(sw, m, "carts.dat", "Open Carts Data File", Read_carts);
					break;
				case Read_category_products:
					do_read(sw, m, "catprd.dat", "Open Catelog/Product File", Read_category_products);
					break;
				case About_info:
					do_about_box(sw);
					break;
				case About_help:
					do_help_box(sw); //VSR part 2
					break;
				case Customers_button: case Carts_button: case Categories_button: case Cart_items_button: case Products_button:
				case Show_categories: case Show_customers: case Show_products:	// RA A.2
					t.set_buffer(m.show_button((Msg_type) window_userdata).c_str());
					break;
				case Show_carts: //VSR part 2
					t.set_buffer(m.show_carts());
					break;
				case Show_cart_items: //VSR part 2
					t.set_buffer(m.show_cart_items());
					break;
				case Show_check_out:
					do_largest_check_out_cart(sw, m);
					break;
				case Show_top_five:
					b2_box(sw, m);
					break;
				case Top3CustomerByPurchaseFrequency:
					do_displayB3(sw, m);
					break;
				case Graph_total_sales_by_customer:						// RT part 2 C3
					do_graph_total_sales_by_customer(sw, m);			// RT part 2 C3
					break;												// RT part 2 C3
				case Graph_total_sales_by_month:						// VSR Part 2 C2
					displayC2(sw,m);									// VSR Part 2 C2
					break;												// VSR Part 2 C2
				case Graph_total_sales_by_category_month:				// RA Part2 C Extra
					do_graph_total_sales_by_category_and_month(sw, m);	// RA Part2 C Extra
					break;												// RA Part2 C Extra
				case Exit_program:
					cout << "save files and exit\n";
					exit(0); //exit program		--RT
					// save to external file not implemented yet
					break;
				default:
					cout << "case not implemented\n";
			}
		}
		return 0;
	}
	catch(exception& e) {
		cerr << "exception: " << e.what() << '\n';
		return 1;
	}
	catch (...) {
		cerr << "Some exception\n";
		return 2;
	}
}
//show about box info window
void do_about_box(Graph_lib::Window& w) 
{
	Graph_lib::Window ab(Point(w.x()+50, w.y()+50), 800, 600, "About Box");
	ab.color(Color::white);
	ab.callback((Fl_Callback*)Menu_Bar_CB, Address (Close_about_box));
	
	Closed_polyline poly_rect1;				//RT
	poly_rect1.add(Point(305,20));			//RT
	poly_rect1.add(Point(460,20));			//RT
	poly_rect1.add(Point(460,55));			//RT
	poly_rect1.add(Point(305,55));			//RT
	poly_rect1.set_style(Line_style(Line_style::solid,4));//RT
	poly_rect1.set_color(Color::dark_cyan);	//RT
	ab.attach(poly_rect1);					//RT

	Closed_polyline poly_rect2;				//RT
	poly_rect2.add(Point(40,100));			//RT
	poly_rect2.add(Point(260,100));			//RT
	poly_rect2.add(Point(260,450));			//RT
	poly_rect2.add(Point(40,450));			//RT
	poly_rect2.set_style(Line_style(Line_style::solid,4));//RT
	poly_rect2.set_color(Color::dark_blue);	//RT
	ab.attach(poly_rect2);					//RT

	Closed_polyline poly_rect3;				//RT
	poly_rect3.add(Point(280,100));			//RT
	poly_rect3.add(Point(500,100));			//RT
	poly_rect3.add(Point(500,450));			//RT
	poly_rect3.add(Point(280,450));			//RT
	poly_rect3.set_style(Line_style(Line_style::solid,4));//RT
	poly_rect3.set_color(Color::dark_blue);	//RT
	ab.attach(poly_rect3);					//RT

	Closed_polyline poly_rect4;				//RT
	poly_rect4.add(Point(520,100));			//RT
	poly_rect4.add(Point(740,100));			//RT
	poly_rect4.add(Point(740,450));			//RT
	poly_rect4.add(Point(520,450));			//RT
	poly_rect4.set_style(Line_style(Line_style::solid,4));//RT
	poly_rect4.set_color(Color::dark_blue);	//RT
	ab.attach(poly_rect4);					//RT

	Text msg(Point(320,50), "About Us");	// RT
	msg.set_color(Color::black);			// RT	
	msg.set_font_size(30);					// RT
	ab.attach(msg);
	
	Text teamName(Point(20,65), "Team: Blue-YZA-18");	// RT
	teamName.set_color(Color::black);			// RT	
	teamName.set_font_size(20);					// RT
	teamName.set_color(Color::magenta);			//RT
	ab.attach(teamName);						//RT

	Image photoRT(Point(50,120),"Robertus Theodore.jpg");	// RT
	ab.attach(photoRT);							//RT
	
	Text nameRT(Point(50,440), "Robertus Theodore");	// RT
	nameRT.set_color(Color::black);			// RT	
	nameRT.set_font_size(20);					// RT
	ab.attach(nameRT);

	Image photoRA(Point(290,120),"Rezan Achmad.jpg");	// RT
	ab.attach(photoRA);							//RT
	
	Text nameRA(Point(290,440), "Rezan Achmad");	// RT
	nameRA.set_color(Color::black);			// RT	
	nameRA.set_font_size(20);					// RT
	ab.attach(nameRA);

	Image photoVR(Point(530,120),"Rajvanshi, Vijay S.jpg");	// RT
	ab.attach(photoVR);							//RT
	
	Text nameVR(Point(530,440), "Rajvanshi, Vijay S");	// RT
	nameVR.set_color(Color::black);			// RT	
	nameVR.set_font_size(20);				// RT
	ab.attach(nameVR);						// RT

	
	wait_for_menu_bar_click();
	ab.detach(msg);//clean up window
	return;
}

//show help box info window
void do_help_box(Graph_lib::Window& w) // VSR Part 2
{
	Graph_lib::Window ab(Point(w.x()+100, w.y()+100), 400, 120, "Help Box");
	ab.color(Color::white);
	ab.callback((Fl_Callback*)Menu_Bar_CB, Address (Close_about_box));
	Text msg(Point(15,50), "Welcome to our online store! This program provides an interface with which you can access, edit, and display information about customers, carts, and categories and products.");
	/*endl << "To begin, first read the necessary data files." << " To do this, you must select the Read button at the top of the drop down menu bar." << 
	endl << "Then, select one of the three options. *Note* Make sure to open the correct files." << 
	endl << "Customer data files should be opened if you have customer selected! " << 
	endl << "Once you have done this, you can display your cart, category, product, cart item, or customer information in two ways. " << 
	endl << "You can either select the large buttons on the main menu or select Show from the drop-down menu and then select your item of choice. " << 
	endl << "In order to find total category, product, or customer sales of a particular category, product, or customer, select Find from the drop-down menu and proceed. " << 
	endl << "In order to add a new cart item, product or customer to the existing list, select Update from the drop-down menu. " << 
	endl << "Finally, to save and exit, select Exit from the drop-down menu." << 
	endl << endl << endl << "Enjoy! -Rezan Achmad, Robertus Theodore, Vijay Rajvanshi");
	*/
	msg.set_color(Color::black);
	ab.attach(msg);
	wait_for_menu_bar_click();
	ab.detach(msg);//clean up window
	return;
}

void do_read(Graph_lib::Window& w, Store_menu& m, string dfn, string msg, Msg_type type)
{
	//Here again we tied our code directly to the FLTK library instead of creating an interface in our Graph_lib interface to FLTK
	//We did it for lack of time, which reflects the real word. Unfortunately if we wanted to move our code to a different graphics
	//library, we have to change our code and not just our Graphic_lib implementation.
	Fl_File_Chooser fc(dfn.c_str(), "*.dat", Fl_File_Chooser::CREATE, msg.c_str());
	fc.show();
	while (fc.shown())
		Fl::wait();	//wait for OK or Cancel button
	if(0!=fc.value())//make sure there is a string to use as a filename
	{
		string fname = fc.value();
		switch(type) {
			case Read_customers:
				m.read_custs(fname);
				break;
			case Read_carts:
				m.read_carts(fname);
				break;
			case Read_category_products:
				m.read_catprds(fname);
				break;
			default:
				throw InvalidType();
		}
	}
	return;
}

// RA Part2 B1
void do_largest_check_out_cart(Graph_lib::Window& w, Store_menu& m) {
	Graph_lib::Window check_out(Point(w.x(), w.y()), 600, 400, "Largest Check out");
	check_out.callback((Fl_Callback*)Menu_Bar_CB, Address (Close_about_box));
	Window_text_display td(Point(10, 20), 580, 360, "", NULL);
	td.set_buffer(m.largest_check_out());

	check_out.attach(td);
	wait_for_menu_bar_click();
	return;
}

void b2_box(Graph_lib::Window& w, Store_menu& m){
	Graph_lib::Window ab(Point(w.x()+100, w.y()+100), 400, 120, "Top Five Products by Sales");
	ab.color(Color::white);
	ab.callback((Fl_Callback*)Menu_Bar_CB, Address (Close_about_box));
	Text msg(Point(15,50), "Top Five Products by Sales");
	Text msg1(Point(15, 100), top_five_product_sales(m.get_cart_items(), m.get_prods()));
	msg.set_color(Color::black);
	msg1.set_color(Color::black);
	ab.attach(msg);
	ab.attach(msg1);
	wait_for_menu_bar_click();
	ab.detach(msg);
	ab.detach(msg1);//clean up window
	return;
	}

// RT Part 2 -Step B
void do_displayB3(Graph_lib::Window& w, Store_menu& m) 
{
	vector<string> result;
	Graph_lib::Window ab(Point(w.x()+50, w.y()+50), 600,400, "Top Three Customer by Purchase Frequency");
	ab.color(Color::white);
	ab.callback((Fl_Callback*)Menu_Bar_CB, Address (Close_about_box));
	
	Text msg(Point(50,50), "Top Three Customer by Purchase Frequency");	// RT-part2-A
	msg.set_color(Color::black);			// RT-part2-A	
	msg.set_font_size(25);					// RT-part2-A
	ab.attach(msg);

	//result = m.top3CustomerByPurchaseFrequency();
	
	Text content1(Point(50,100), m.top3CustomerByPurchaseFrequency());	// RT-part2-A
	content1.set_color(Color::black);			// RT-part2-A	
	content1.set_font_size(20);					// RT-part2-A
	ab.attach(content1);
	
	wait_for_menu_bar_click();
	ab.detach(msg);//clean up window
	return;
}

// RA Part2 C Extra
void do_graph_total_sales_by_category_and_month(Graph_lib::Window& w, Store_menu& m) {	// RA Part2 C extra
	// Get year
	const char* s_year = fl_input("Enter Year", "2010");
	if (s_year == NULL) {
		return;
	}

	// Define var
	int year = atoi(s_year);

	Point padding(50, 100);
	int y_length = 300;
	int x_length = 480;
	Point zero_point(30 + padding.x, y_length + padding.y);

	int win_w = zero_point.x + x_length + 300;
	int win_y = zero_point.y + 100;

	// Create window
	Graph_lib::Window win(Point(w.x(), w.y()), win_w, win_y, "Graph Total Sales by Category and Month");
	win.callback((Fl_Callback*)Menu_Bar_CB, Address (Close_graph_total_sales_by_category_and_month));

	// Show Title
	ostringstream oss;
	oss << "Total Sales in " << year;
	Text* title =  new Text(Point((win_w - 300) / 2, 40), oss.str());
	title->set_font_size(20);
	win.attach(*title);

	// Build data graph
	vector<Category> cats = m.get_cats();
	vector<vector<int>> sales_per_month_per_category;
	vector<double> sales_per_month;

	for (int month = 1; month <= 12; ++month) {
		vector<int> sales_category;
		double total = 0, temp = 0;

		for (vector<Category>::iterator it = cats.begin(); it != cats.end(); ++it) {
			temp = m.total_sales(it->get_cat_id(), year, month);
			sales_category.push_back(temp);
			total += temp;
		}

		sales_per_month_per_category.push_back(sales_category);
		sales_per_month.push_back(total);
	}

	// Draw graph
	double width = 20;
	for (int i = 0; i < 12; ++i) {
		double total_height = 0;

		if (sales_per_month[i] <= 0) {
			// Skip
			continue;
		}

		for (int j =0; j < sales_per_month_per_category[i].size(); ++j) {
			// Height
			double height = (sales_per_month_per_category[i][j] / sales_per_month[i]) * (double) 300;
			
			if (height <= 0) {
				// Skip
				continue;
			} else if (height <= 1) {
				// Round
				height = 1;
			} else {
				// Round
				if (height - (int) height >= 0.5) {
					height = (int) height + 1;
				} else {
					height = (int) height;
				}
			}

			// X
			double x = zero_point.x + (i + 1) * 40 - 10;

			// Y
			double y = zero_point.y - y_length + total_height;

			// Accumulate height
			total_height += height;

			// Attach Bar
			Graph_lib::Rectangle* r = new Graph_lib::Rectangle(Point((int) x, (int) y), (int) width, (int) height);
			r->set_fill_color(j + 1);
			r->set_color(j+1);
			win.attach(*r);
		}
	}

	// Show Axis
	Axis xa(Axis::x, zero_point, x_length, 12, "Month");
	win.attach(xa);

	Axis ya(Axis::y, zero_point, y_length, 10, "Percentage");
    win.attach(ya);

	// Show label percent
	for (int i = 1; i <= 10; ++i) {
		ostringstream oss;
		oss << i * 10 << " %";
		Text* t = new Text(Point(0, 0), oss.str());
		t->set_font_size(8);
		t->move(zero_point.x - 20, zero_point.y - i * (y_length / 10) + (t->font_size() / 2));
		win.attach(*t);
	}

	// Show label month
	for (int i = 1; i <= 12; ++i) {
		ostringstream oss;
		oss << i;
		Text* t = new Text(Point(0, 0), oss.str());
		t->set_font_size(8);
		t->move(zero_point.x + i * (x_length / 12) - (t->font_size() / 2), zero_point.y + t->font_size() + 1);
		win.attach(*t);
	}

	// Show Legend
	vector<string> data;
	for (vector<Category>::iterator it = cats.begin(); it != cats.end(); ++it) {
		data.push_back(it->get_cat_name());
	}
	Legend legend(Point(zero_point.x + x_length + 50, padding.y), data, "Legend");
	win.attach(legend);

	wait_for_menu_bar_click();
	return;
}

//RT part 2 C3
void do_graph_total_sales_by_customer(Graph_lib::Window& w, Store_menu& m) {	//RT part 2 C3

	// Validate data
	if (m.get_custs().size() < 1) {
		fl_alert("Cutomers are empty");
		return;
	}
	if (m.get_carts().size() < 1) {
		fl_alert("Carts are empty");
		return;
	}
	if (m.get_cart_items().size() < 1) {
		fl_alert("Cart Items are empty");
		return;
	}

	Point padding(50, 100);
	int y_length = 300;
	int x_length = 800;
	Point zero_point(30 + padding.x, y_length + padding.y);

	int win_w = zero_point.x + x_length + 300;
	int win_y = zero_point.y + 200;

	// Create window
	Graph_lib::Window win(Point(w.x(), w.y()), win_w, win_y, "Graph Total Sales by Customer");
	win.callback((Fl_Callback*)Menu_Bar_CB, Address (Close_graph_total_sales_by_category_and_month));
	// title
	Text msg(Point(50,50), "Graph Total Sales by Customer");	
	msg.set_color(Color::black);			
	msg.set_font_size(25);					
	win.attach(msg);


	// Calculate and Prepare data
	const int nSize = 20;
	int custId [nSize];			// temporary array for sorted customer id 	
	int count [nSize];			// temporary array for sorted total sales each Customer 	
	String custName [nSize];	// temporary array for sorted customer Name 	

	int k,j,l = 0;
	bool assign = false;		// for checking trough vector
	vector<Cart> carts = m.get_carts();
	vector<Cart_item> cart_item = m.get_cart_items();
	vector<Customer> custs = m.get_custs();

	// init array with default value
	for (int i = 0 ; i<nSize ; i++){
		custId[i] = 9999;
	}
	for (int i = 0 ; i<nSize ; i++){
		count[i] = 0;
	}
	for (int i =0; i<nSize; i++){
		custName[i]= "";
	}

	// assign array temporary with data counting (purchase frequency)
	for (k=0; k<carts.size(); k++){
		// check existing custID in temporary array
		for (j=0;j<19;j++){
			if(carts[k].get_cust_id() == custId[j]){
				count[j]++;
				assign = true;
				break;
			}
			else {
				continue;
			}
		}
		// add new if not exist
		while (assign== false){
			if(custId[l] == 9999 ){
				custId[l] = carts[k].get_cust_id();
				count[l]++;
				assign = true;
				break;
			}
			else{
				l++;
			}
		}
		assign = false;
	}

	// table cust id and count appearance already establish
	//Sorting the rest of table
	
	// Step through each element of the array
	for (int nStartIndex = 0; nStartIndex <nSize; nStartIndex++)
	{
		// we've encountered so far.
		int nLargestIndex = nStartIndex;
		for (int nCurrentIndex = nStartIndex + 1; nCurrentIndex < nSize; nCurrentIndex++)
		{
			// Check smaller
			if (count[nCurrentIndex] > count[nLargestIndex])
				nLargestIndex = nCurrentIndex;
		}
		swap(count[nLargestIndex],count[nStartIndex] );
		swap(custId[nLargestIndex],custId[nStartIndex] );
	}


	// get customer name and Count totalCustomer
	int totalCustomer= 0;
	for (int x = 0 ; x < nSize ; x++){
		if (custId[x] == 9999){
			break;
		}
		else {
			for (int r = 0; r < custs.size(); r++){
				if(custs[r].get_cust_id()== custId[x]){
					custName[x] = custs[r].get_cust_name();
					totalCustomer++;
				}
			}
		}
	}
	
	/*
	String v;
	for (int p = 0 ; p<nSize; p++){
		if(custName[p] == ""){
			break;
		}
		else{
			v = v+ " "+ custName[p];
		}
	}
	Text msg2(Point(80,500), v);	
	msg2.set_color(Color::black);			
	msg2.set_font_size(10);					
	win.attach(msg2);
	*/
	//end of data preparation


	// Show Axis
	Axis xa(Axis::x, zero_point, x_length, totalCustomer, "Customer");
	win.attach(xa);
	Axis ya(Axis::y, zero_point, y_length, 10, "Total Sales");
    win.attach(ya);

	// Show label Total Sales
	for (int i = 1; i <= 10; ++i) {
		ostringstream oss;
		oss << i;
		Text* t = new Text(Point(0, 0), oss.str());
		t->set_font_size(10);
		t->move(zero_point.x - 20, zero_point.y -i *(y_length/10) + (t->font_size() / 2));
		win.attach(*t);
	}

	// Show label customer
	for (int i = 1; i <= totalCustomer; ++i) {
		ostringstream oss;
		oss <<custName[i-1];
		Text* t = new Text(Point(0, 0), oss.str());
		t->set_font_size(10);
		t->move(zero_point.x + i * (x_length / totalCustomer) - (t->font_size() / 2), zero_point.y + t->font_size() + 1);
		win.attach(*t);
	}

	// Draw Graph
	double width = 20;	//width of rectangle
	for (int u = 1; u<= totalCustomer; u++){
		int height = count[u-1]*(y_length/10);	
		// X
		double x = zero_point.x + (u) * (x_length/totalCustomer) - 10;
		// Y
		double y = zero_point.y - height;

		// Attach Bar
		Graph_lib::Rectangle* r = new Graph_lib::Rectangle(Point((int) x, (int) y), (int) width, height);
		r->set_fill_color(Color::dark_magenta);
		r->set_color(Color::dark_magenta);
		win.attach(*r);
	}

	wait_for_menu_bar_click();
	return;
}

// VSR Part 2 C2
void displayC2(Graph_lib::Window& w, Store_menu& m) {

	// Validate data
	if (m.get_carts().size() < 1) {
		fl_alert("Carts are empty");
		return;
	}
	if (m.get_prods().size() < 1) {
		fl_alert("Products are empty");
		return;
	}
	if (m.get_cart_items().size() < 1) {
		fl_alert("Cart Items are empty");
		return;
	}

	int x_spacing = 40;

//Build Data for Graph
vector<Cart> carts = m.get_carts();
vector<Product> prods = m.get_prods();
vector<Cart_item> cart_items = m.get_cart_items();

double totalsales = 0;
vector<double> sales_organized_by_month (12);
int numberofmonths = 12;
double max_sales = 0;

for(int i=0; i<carts.size(); i++)
{
	for(int j=1; j<=numberofmonths; j++)
		{if (carts[i].get_cart_purchase_date().month() == j)
		{
			for (int k=0; k<cart_items.size(); k++)
			{
				if (carts[i].get_cart_id()==cart_items[k].get_cart_id())
					{
						for(int l=0; l<prods.size(); l++)
						{
							if(cart_items[k].get_prod_id() == prods[l].get_prod_id())
							{totalsales = totalsales + cart_items[k].get_prod_qty()*prods[l].get_prod_price();
								sales_organized_by_month[j-1] += totalsales;
								totalsales=0;
							}
						}
					}
			}
		}
		}

}

max_sales = *max_element(sales_organized_by_month.begin(), sales_organized_by_month.end());
	
	//Make window
	Graph_lib::Window ab(Point(w.x()+100, w.y()+100), 1000, 600, "Cart Sales by Month");
	// ab.color(Color::black);
	ab.callback((Fl_Callback*)Menu_Bar_CB, Address (Close_about_box));

	// Show Title
	ostringstream oss;
	oss << "Total Sales for Each Month";
	Text* title =  new Text(Point(200, 40), oss.str());
	title->set_font_size(20);
	ab.attach(*title);

	// Show Axis
	
	Axis xaxis(Axis::x, Point(50,500), 480, 12, "Month");
	Axis yaxis(Axis::y, Point(50,500), 480, 10, "Total Sales");
	ab.attach(xaxis);
	ab.attach(yaxis);

	//Legend
	ostringstream oss1;
	oss1 << "Each notch above Month goes from 1-12, Jan to Dec.";
	Text msg1(Point(550,50), oss1.str());	// VSR
	msg1.set_color(Color::white);			// VSR
	msg1.set_font_size(16);					// VSR
	ab.attach(msg1);

	oss1.clear(); oss1.str("");
	oss1 << "The Total Sales scale goes from 0 to " << max_sales << ".";
	Text msg2(Point(550,75), oss1.str());	// VSR
	msg2.set_color(Color::white);			// VSR
	msg2.set_font_size(16);					// VSR
	ab.attach(msg2);

	oss1.clear(); oss1.str("");
	oss1 << "Each notch represents an interval of " << max_sales/10 << " dollars.";
	Text msg3(Point(550,100), oss1.str());	// VSR
	msg3.set_color(Color::white);			// VSR
	msg3.set_font_size(16);					// VSR
	ab.attach(msg3);

	// Draw Graph
	int width = 20;	//width of rectangle
	int zero_point_x = 50;
	int zero_point_y = 500;
	for (int i = 0; i <= 11; i++){
		int height = (sales_organized_by_month[i]/max_sales)*(480);	
		int x = zero_point_x + (i)*(x_spacing)+ 20;
		int y = zero_point_y - height;

		// Attach Bar
		Graph_lib::Rectangle* r = new Graph_lib::Rectangle(Point(x,y), width, height);
		r->set_fill_color(Color::dark_magenta);
		r->set_color(Color::dark_magenta);
		ab.attach(*r);
	}
	
	

	
wait_for_menu_bar_click();
	ab.detach(msg1);
	ab.detach(xaxis);
	ab.detach(yaxis);
	ab.detach(*title);
	return;

	}


